package com.tianji.learning.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.service.ISignRecordService;
import org.checkerframework.checker.units.qual.K;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
@Transactional(rollbackFor = Exception.class)
public class SignRecordServiceImpl implements ISignRecordService {



    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RabbitMqHelper rabbitMqHelper;

    //1. 获取当月、当天日期，组装key
    //2. 查询redis签到数据
    //3. 如果没有签到数据，返回空
    //4. 如果有签到数据，获取bitmap数据
    //5. 返回结果
    @Override
    public char[] findSignRecords() {
        //1. 获取当月、当天日期，组装key
        //1-1 获取当月
        String yyyyMM = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
        //1-2 当天日期
        int currentDay = LocalDate.now().getDayOfMonth();
        //1-3 组装key
        String key = "sign:" + UserContext.getUser() + ":" + yyyyMM;
        //2. 查询redis签到数据
        List<Long> list = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(currentDay)).valueAt(0)
        );
        //3. 如果没有签到数据，返回空
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        //4. 如果有签到数据，获取bitmap数据
        //4-1 获取十进制
        Long allSign = list.get(0);
        //4-2 转二进制
        String s = Long.toBinaryString(allSign);
        //4-3 前面补0
        String s1 = StrUtil.padPre(s, currentDay, "0");
        //5. 返回结果
        return s1.toCharArray();
    }


    //1.获取当月、当天日期，组装Key
    //2.保存redis签到数据
    //3.计算连续签到奖励积分
    //4.发送MQ消息，新增积分 TODO
    //5.封装并返回SignResultVO
    @Override
    public SignResultVO addSignRecords() {
        //1. 获取当月、当天日期，组装key
        //1-1 获取当月
        String yyyyMM = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
        //1.2 当天日期
        int currentDay = LocalDate.now().getDayOfMonth();
        //1-3 组装key
        String key="sign:"+UserContext.getUser()+":"+yyyyMM;
        //2.保存redis签到数据
        Boolean oldValue = stringRedisTemplate.opsForValue().setBit(key, currentDay - 1, true);
        if(oldValue){
            throw new BizIllegalException("不能重复签到");
        }
        //3. 计算连续签到奖励积分
        //3-1 获取连续签到天数
        Integer signDays= getSignDays(key,currentDay);
        //3-2 计算连续签到奖励积分
        Integer rewardPoints=0;
        switch (signDays) {
            case 7:{
                rewardPoints=10;
                break;
            }
            case 14:{
                rewardPoints=20;
                break;
            }
            case 28: {
                rewardPoints=40;
                break;
            }
        }
        //4. 发送MQ消息，新增积分 TODO
        PointsRecord pointsRecord = new PointsRecord();
        pointsRecord.setUserId(UserContext.getUser());
        pointsRecord.setType(PointsRecordType.SIGN);
        pointsRecord.setPoints(rewardPoints+1);//签到积分是基本积分+奖励积分
        rabbitMqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.SIGN_IN,
                pointsRecord);

        //5.封装并返回SignResultVO
        SignResultVO signResultVO = new SignResultVO();
        signResultVO.setSignDays(signDays);
        signResultVO.setRewardPoints(rewardPoints);
        return signResultVO;
    }

    //获取连续签到天数
    private Integer getSignDays(String key, int currentDay) {
        //1.查询redis签到数据
        List<Long> list = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(currentDay)).valueAt(0)
        );
        //2. 如果没有签到数据，0
        if(CollUtil.isEmpty(list)){
            return 0;
        }
        //3.如果有签到数据，获取bitmap数据
        //3-1获取十进制
        Long allSign = list.get(0);
        //3-2 转二进制
        String s = Long.toBinaryString(allSign);
        //3-3 前面补0
        String s1 = StrUtil.padPre(s, currentDay, "0");
        //4.字符串反转 00000 101100
        String s2=StrUtil.reverse(s1);
        // 获取0出现的位置
        int i=s2.indexOf("0");
        if(i==-1){
            //如果全是1则直接返回今天的日期
            return currentDay;
        }else {
            return i;
        }

    }
}
